package edu.arizona.mindseye.swing;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;

import edu.arizona.mindseye.Annotation;
import edu.arizona.mindseye.VideoModel;
import edu.arizona.mindseye.event.Event;
import edu.arizona.mindseye.event.EventListener;
import edu.arizona.mindseye.event.EventManager;
import edu.arizona.mindseye.event.enums.EventType;
import edu.arizona.mindseye.event.enums.Parameter;

public class TimelinePanel {

	private JComponent _parent;
	
	private RenderingPanel _renderingPanel;
	private JButton _mark;
	private JButton _clear;
	
	private int _id;
	private int _selectedIndex = -1;
	private List<Annotation> _annotations;
	private List<Rectangle2D> _rectangles;

	private double _x;
	private int _maxTime;
	
	private VideoModel _model;
	private List<String> _behaviors;
	
	public TimelinePanel(int id) { 
		_id = id;
		
		_annotations = new ArrayList<Annotation>();
		_rectangles = new ArrayList<Rectangle2D>();

		_mark = new JButton("Mark");
		_clear = new JButton("Clear");
		
		_renderingPanel = new RenderingPanel();

		addListeners();
	}
	
	public void addTo(JComponent component, int y) { 
		_parent = component;
		
		component.add(_renderingPanel, GBC.makeGBC(0, y, GridBagConstraints.BOTH, new Insets(5,5,5,5), 1, 0));
		component.add(_mark, GBC.makeGBC(1, y, GridBagConstraints.BOTH, 0, 0));
		component.add(_clear, GBC.makeGBC(2, y, GridBagConstraints.BOTH, 0, 0));
	}
	
	private void addListeners() { 
		_mark.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				int min = 0;
				for (Annotation a : _annotations) { 
					min = Math.max(min, a.max());
				}
				
				int max = _model.getIndex();
				if (max == min) { 
					JOptionPane.showMessageDialog(null, "Change the frame index before inserting a break");
					return;
				}

				BehaviorsDialog dialog = new BehaviorsDialog(_behaviors);
				dialog.setVisible(true);
				
				if (dialog.okPressed()) { 
					Annotation a = new Annotation(_id, min, max);
					a.set(dialog.getBehaviors());
					
					addAnnotation(a);
				}
				
			} 
		});
		
		_clear.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				_annotations.clear();
				_rectangles.clear();
				_selectedIndex = -1;
				_x = 0;
				
				_parent.repaint();
			} 
		});
		
		EventManager.inst().register(EventType.MOVIE_LOADED, new EventListener() {
			@Override
			public void onEvent(Event e) {
				_maxTime = (Integer) e.getValue(Parameter.frames);
				_model = (VideoModel) e.getValue(Parameter.model);
				
				_annotations.clear();
				_rectangles.clear();
				_selectedIndex = -1;
				_x = 0;

				_parent.repaint();
			}
		});
		
		
		EventManager.inst().register(EventType.BEHAVIORS, new EventListener() {
			@Override
			public void onEvent(Event e) {
				_behaviors = (List<String>) e.getValue(Parameter.behaviors);
			}
		});
	}
	
	public List<Annotation> getAnnotations() { 
		return _annotations;
	}
	
	public void clearSelection() { 
		_selectedIndex = -1;
		_parent.repaint();
	}
	
	private void addAnnotation(Annotation a) { 
		_annotations.add(a);
		
		double ratio = (double) (a.max() - a.min()) / (double) _maxTime;
		_rectangles.add(new Rectangle2D.Double(_x, 0, ratio, 1));
		
		_x += ratio;
		_parent.repaint();
	}

	class RenderingPanel extends JPanel implements MouseListener { 
		
		public RenderingPanel() { 
			super();
			
			setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
			addMouseListener(this);
		}

		@Override
		public void paintComponent(Graphics graphics) { 
			Graphics2D g = (Graphics2D) graphics;

			Font f = g.getFont();
			g.setFont(f.deriveFont(9));
			
			g.setColor(Color.white);
			g.fillRect(0, 0, getWidth(), getHeight());

			double w = getWidth();
			double h = getHeight();

			Rectangle2D rect = null;
			Color[] colors = new Color[] { new Color(0.68f,0.68f,1.0f,1f), new Color(0.75f,0.75f,1.0f,1f) } ;
			for (int i = 0; i < _annotations.size(); ++i) { 
				
				Rectangle2D r = _rectangles.get(i);
				Annotation a = _annotations.get(i);
				
				g.setColor(colors[i%2]);
				g.fill(new Rectangle2D.Double(r.getX()*w, 0, r.getWidth()*w, h));
				if (_selectedIndex == i)  {
					rect = new Rectangle2D.Double((r.getX()*w)+1, 3, (r.getWidth()*w)-2, h-7);
				} else { 
					g.setColor(Color.black);
					g.drawString(a.toString(), (float) (r.getX()*w + 8), 13f);
				}
			}

			if (rect != null) { 
				g.setStroke(new BasicStroke(2f));
				g.setColor(Color.black);
				g.draw(rect);
			}
		}

		@Override
		public void mouseClicked(MouseEvent arg0) {
			System.out.println(arg0.getX() + " -- " + arg0.getY());

			int index = -1;
			for (int i = 0; i < _rectangles.size(); ++i) { 
				Rectangle2D r = _rectangles.get(i);
				Rectangle2D newR = new Rectangle2D.Double(r.getX()*getWidth(), 0, r.getWidth()*getWidth(), getHeight());
				
				if (newR.contains(arg0.getX(), arg0.getY())) {
					index = i;
				}
			}
			
			if (_selectedIndex != index)  {
				_selectedIndex = index;
				
				Event event = new Event(EventType.SELECTED_ANNOTATION);
				event.addParameter(Parameter.id, _id);
				event.addParameter(Parameter.index, _selectedIndex);
				event.addParameter(Parameter.annotation, _annotations.get(_selectedIndex));
				EventManager.inst().dispatch(event);
				
				repaint();
			}
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {}

		@Override
		public void mouseExited(MouseEvent arg0) {}

		@Override
		public void mousePressed(MouseEvent arg0) {}

		@Override
		public void mouseReleased(MouseEvent arg0) {}
	}
}

